package jmine.tec.utils.sql;

import java.lang.reflect.Proxy;
import java.sql.Connection;
import java.sql.SQLException;

import javax.sql.DataSource;

import org.springframework.beans.factory.FactoryBean;

/**
 * Um wrapper para {@link DataSource} que faz o tracking de conexoes abertas e expoe via JMX
 * 
 * @author takeshi
 */
public class TrackingDataSourceFactoryBean implements FactoryBean {

    private DataSource delegate;

    /**
     * {@inheritDoc}
     */
    public Object getObject() throws Exception {
        return Proxy
                .newProxyInstance(getClass().getClassLoader(), new Class[]{ DataSource.class }, new DataSourceOverridingProxy(delegate));
    }

    /**
     * {@inheritDoc}
     */
    public Class getObjectType() {
        return DataSource.class;
    }

    /**
     * {@inheritDoc}
     */
    public boolean isSingleton() {
        return true;
    }

    /**
     * @return the delegate
     */
    public DataSource getDelegate() {
        return delegate;
    }

    /**
     * @param delegate the delegate to set
     */
    public void setDelegate(DataSource delegate) {
        this.delegate = delegate;
    }

    /**
     * @author takeshi
     */
    public static class DataSourceOverridingProxy extends ProxyOverridingInvocationHandler {

        /**
         * C'tor
         * 
         * @param delegate Object
         */
        public DataSourceOverridingProxy(Object delegate) {
            super(delegate);
        }

        /**
         * {@inheritDoc}
         */
        public Connection getConnection() throws SQLException {
            Connection conn = ((DataSource) getDelegate()).getConnection();
            return (Connection) Proxy.newProxyInstance(getClass().getClassLoader(), new Class[]{ Connection.class }, new ConnectionWrapperInvocationHandler(
                    conn));
        }

        /**
         * {@inheritDoc}
         */
        public Connection getConnection(String username, String password) throws SQLException {
            Connection conn = ((DataSource) getDelegate()).getConnection(username, password);
            return (Connection) Proxy.newProxyInstance(getClass().getClassLoader(), new Class[]{ Connection.class }, new ConnectionWrapperInvocationHandler(
                    conn));
        }

    }

}
